﻿using System;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using woaC2.Common;
using woaC2.LogicLib;
using woaC2.LogicLib.GlobalShare;
using System.Data.Linq;
using System.Collections.Generic;
using woaPoker.LogicLib.LogicCtrl;
using Newtonsoft.Json;

namespace woaC2.SocketLib
{
    public sealed class SocketServer
    {
        #region Singletone

        private SocketServer()
        {

        }
        
        public static SocketServer Instance
        {
            get { return Nested.instance; }
        }

        private class Nested
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static Nested()
            {
            }

            internal static readonly SocketServer instance = new SocketServer();
        }

        #endregion

        #region Private

        private IMessageServer _messageServer;

        private bool _IsStart;

        #endregion
        
        #region Khởi tạo server Socket
        /// <summary>
        /// Khởi tạo socket
        /// </summary>
        /// <param name="port"></param>
        public bool InitSocket(ushort port)
        {
            if (this._IsStart) return false;

            if (_messageServer == null)
            {
                _messageServer = new MessageServer(IPAddress.Any, port, AssetsGS.instance.SocketConfig_MaxxCCU);
                
                _messageServer.ClientConnected += this.ProcessServer_ClientConnected;
                _messageServer.ClientDisconnected += this.ProcessServer_ClientDisconnected;
                _messageServer.MessageRecieved += this.ProcessServer_MessageRecieved;
            } 
            ThreadPool.QueueUserWorkItem(o => _messageServer.Start());

            
            this._IsStart = true;
            return true;
        }
        #endregion 

        #region Dừng Socket
        /// <summary>
        /// Dừng socket
        /// </summary>
        /// <param name="port"></param>
        public bool StopSocket()
        {
            if (!_IsStart) return false;
            ThreadPool.QueueUserWorkItem(o =>_messageServer.Stop());
            this._IsStart = false;
            return true;
        }
        #endregion

        #region Lấy số lượng client connect tới Server
        /// <summary>
        /// Get CCU
        /// </summary>
        public ushort CCU
        {
            get
            {
                return this._messageServer.CCU;
            }
        }
        #endregion

        #region Đặt số lượng MaxCCU
        public void SetMaxCCU(ushort maxCCU)
        {
            this._messageServer.MaxCCU = maxCCU;
        }
        #endregion 

        #region Gửi thông tin cho tất cả các Client trong 1 trận đấu
        public bool BroadcastToClientInMatch(Match match, string mess)
        {
            foreach (Player player in match.listPlayer1)
            {
                SocketServer.Instance.SendToClient(player.client.SessionID, mess);
            }
            foreach (Player player in match.listPlayer2)
            {
                SocketServer.Instance.SendToClient(player.client.SessionID, mess);
            }
            return true;
        }
        #endregion

        #region gửi thông tin cho các Client trong 1 trận đấu nhưng ko gửi cho Client gọi Hàm
        public void Broadcast(Match match,Guid sessionId, string mess)
        {
            foreach (Player player in match.listPlayer1)
            {
                if (player.client.SessionID != sessionId)
                {
                    SocketServer.Instance.SendToClient(player.client.SessionID, mess);
                }
            }

            foreach (Player player in match.listPlayer2)
            {
                if (player.client.SessionID != sessionId)
                {
                    SocketServer.Instance.SendToClient(player.client.SessionID, mess);
                }
            }

        }

        #endregion

        #region Gửi Broadcast cho tất cả Client nhưng ko gửi cho 1 Client gọi hàm
        public void Broadcast(Guid sessionId, string mess)
        {
            IList<Client> List = ClientRegistry.instance.GetAll();
            foreach (Client client in List)
            {
                if (client.SessionID != sessionId)
                {
                    SocketServer.Instance.SendToClient(client.SessionID, mess);
                }
            }
        }

        #endregion
        #region Broadcast cho tất cả các Client

        public bool Broadcast(string mess)
        {
            IList<Client> List = ClientRegistry.instance.GetAll();
            foreach (Client client in List)
            {
                
                SocketServer.Instance.SendToClient(client.SessionID, mess);
            }
            return true;
        }
        #endregion

        #region Gửi bản tin đến client
        public bool SendToClient (Guid sessionId, string mess)
        {
            _messageServer.SendMessageToClient(sessionId, Encoding.ASCII.GetBytes(mess));
            return true;
        }
        #endregion
        #region Event Client Connected
        /// <summary>
        /// Sự kiện 1 client connect đến ServerSocket
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessServer_ClientConnected(object sender, ClientStatusChangedEventArgs e)
        {
            try
            {
                Log.WriteOnScreen2("Client:({0}:{1}) Authentication....", e.ClientIP, e.ClientPort);
            }
            catch (Exception ex)
            {
                Log.WriteError("SocketServer.ProcessServer_ClientConnected--" + ex);
            }
        }
        #endregion 

        #region Event Client Disconnected
        /// <summary>
        /// Sự kiện 1 client dừng kết nối đến ServerSocket
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessServer_ClientDisconnected(object sender, ClientStatusChangedEventArgs e)
        {
            try
            {
                //Chu phong disconnect

                if (MathRegistry.instance.GetMatchById(e.sessionId) != null)
                {
                    //tran dau chua bat dau
                    if (MathRegistry.instance.GetMatchById(e.sessionId).status != true)
                    {
                        MathRegistry.instance.Remove(e.sessionId);
                        //sendsomthing
                        var jsonOut = "mes001$";
                        var mesOut = FunctionCmn.StampMessage(jsonOut);
                        SocketServer.Instance.BroadcastToClientInMatch(MathRegistry.instance.GetMatchById(e.sessionId), mesOut);
                    }
                    else
                    {
                        MathRegistry.instance.GetMatchById(e.sessionId).listPlayer1.Remove(PlayerRegistry.instance.GetPlayer(e.sessionId));
                        MathRegistry.instance.GetMatchById(e.sessionId).listPlayer2.Remove(PlayerRegistry.instance.GetPlayer(e.sessionId));
                        //sendsometing
                        var jsonOut = "mes001$";
                        var mesOut = FunctionCmn.StampMessage(jsonOut);
                        SocketServer.Instance.BroadcastToClientInMatch(MathRegistry.instance.GetMatchById(e.sessionId), mesOut);
                    }

                }
                //nguoi choi disconnect
                else
                {
                    PlayerRegistry.instance.Remove(e.sessionId);
                    var jsonOut = "mes001$";
                    var mesOut = FunctionCmn.StampMessage(jsonOut);
                    //nguoi choi tronng phong hoac phong doi
                    if (MathRegistry.instance.FindMatchByPlayerId(e.sessionId) != null)
                    {
                        SocketServer.Instance.BroadcastToClientInMatch(MathRegistry.instance.FindMatchByPlayerId(e.sessionId), mesOut);
                    }
                    else
                        Log.WriteOnScreen2("Client:({0}:{1}) disconnect.", e.ClientIP, e.ClientPort);
                }
            }
            catch (Exception ex)
            {
                Log.WriteError("SocketServer.ProcessServer_ClientDisconnected--" + ex);
            }
        }
        #endregion

        #region Event Recieved
        /// <summary>
        /// Sự kiện khi 1 client gửi mes đến server
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessServer_MessageRecieved(object sender, MessageRecievedEventArgs e)
        {
            try
            {
                if (!e.Message.Any()) return;

                string methodName;
                string jsonIn;

                var mesIn = Encoding.ASCII.GetString(e.Message);

                if (!FunctionCmn.IntegrityChk(mesIn, out methodName, out jsonIn))
                    return;

                var jsonOut = "evt"+Service.Call(e.sessionId, methodName, jsonIn);

                var mesOut = FunctionCmn.StampMessage(jsonOut);

                _messageServer.SendMessageToClient(e.sessionId, Encoding.ASCII.GetBytes(mesOut));

            }
            catch (Exception ex)
            {
                Log.WriteError("SocketServer.ProcessServer_MessageRecieved--" + ex);
            }
        }
        #endregion
    }
}
